2021.2 星期 :
koa-router
##
3. 多个中间件
1 | router.get('/admin/:user/*', (ctx, next) => { |
API
- router.routes()
返回一个中间件,这个中间件根据请求分派路由 router.allowedMethods([options])
根据不同类型(也就是 options 参数)的请求允许请求头包含的方法,返回不同的中间件,以及响应 405 [不被允许] 和 501 [未实现]
options => {throw: true} 抛出错误而不是设置返回状态码 statue 和标头 header
options => {notImplemented: () => returnedValue} 使用这个函数抛出的值代替原来的 notImplemented 501 未实现错误
options => {methodNotAllowed: () => returnedValue} 使用这个函数抛出的值代替原来的 notImplemented 405 不被允许错误1
2
3
4
5
6
7
8
9
10
11
12
13
14// 官网例子
const Koa = require('koa');
const Router = require('koa-router');
const Boom = require('boom');
const app = new Koa();
const router = new Router();
app.use(router.routes());
app.use(router.allowedMethods({
throw: true,
notImplemented: () => new Boom.notImplemented(),
methodNotAllowed: () => new Boom.methodNotAllowed()
}));router.use([path], middleware)
在路由中使用中间件,中间件运行的顺序是 .use() 方法调用的顺序
path 允许调用中间件的路径,可以是一个路径字符串,也可以是路径组成的数组,不设置表示所有路径都可以使用
middleware 要使用的中间件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const admin = new Router({
prefix: '/admin'
});
admin.use(['/default/:user', '/test'], (ctx, next) => {
ctx.body = 'in admin\n';
ctx.body += ctx._matchedRoute + '--' + ctx.params.user + '\n';
next();
})
admin.get('/**', (ctx) => {
ctx.body += 'finish\n';
})
app.use(admin.routes());
app.use(admin.allowedMethods());router.prefix(prefix)
返回一个子路由,这个路由挂载在 router 上,并且设置了 prefix 前缀- router.redirect(source, destination, code)
重定向资源 source 到目的地地址 destination 使用 30x 状态码(code 定义) - router.param(param, middleware)
给路由参数 param 添加中间件,后续 router 路径中 含有 这个参数的,都会首先触发这个中间件,一般用于自动验证等
1 | admin |
其他中间件
## 统一返回格式 & 错误处理
在实现错误处理和统一返回格式之前,我们再做一点小小的改造。前面我们创建了 config 目录,里面存了一些常量配置,
接下来我们还会创建一个 common/utils.js 用来存放工具函数,
如果每个引用到的地方都 require 来引入是比较麻烦的,
所以我们把工具函数和常量配置放到 app.context 的属性上,之后就不用频繁引入了,可以通过 ctx.来访问
登录
koa-passport,koa-session中间件之
compose
这里引入了一个插件 koa-compose,作用是简化引用中间件的写法。到这里准备工作已经做好了,开始处理参数解析的问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const Koa = require('koa');
const compose = require('koa-compose');
const MD = require('./middlewares/');
const app = new Koa();
const port = '8082'
const host = '0.0.0.0'
app.use(compose(MD));
app.listen(port, host, () => {
console.log(`API server listening on ${host}:${port}`);
});
koa-bodyparser
1 | const koaBody = require('koa-bodyparser'); |
cors
1 | /** |
koa-router 是可以添加多个路由级中间件的,我们将参数校验放在这里处理。
然后我们添加新的目录 schema,用来存放参数校验部分的代码,添加两个文件
@hapi/joi
app/middlewares/ 下添加 paramValidator.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32module.exports = paramSchema => {
return async function (ctx, next) {
let body = ctx.request.body;
try {
if (typeof body === 'string' && body.length) body = JSON.parse(body);
} catch (error) {}
const paramMap = {
router: ctx.request.params,
query: ctx.request.query,
body
};
if (!paramSchema) return next();
const schemaKeys = Object.getOwnPropertyNames(paramSchema);
if (!schemaKeys.length) return next();
// eslint-disable-next-line array-callback-return
schemaKeys.some(item => {
const validObj = paramMap[item];
const validResult = paramSchema[item].validate(validObj, {
allowUnknown: true
});
if (validResult.error) {
ctx.utils.assert(false, ctx.utils.throwError(9998, validResult.error.message));
}
});
await next();
};
};
1 | // app/index.js |
koa
中间价
中间件使用
中间件是一个函数(异步或者同步)处在 HTTP request(请求)与 HTTP response (响应)之间,用来实现某种中间功能 app.use() 来加载中间件。基本上,Koa 所有功能都是通过中间件来实现的,中间件函数会被传入两个参数:1) ctx context 对象,表示一次对话的上下文(requset和response);2) next 函数,调用 next 函数可以把执行权交给下一个中间件,下一个中间件执行完会把执行权再交回上一个中间件。如果中间件中有异步操作,需要使用 async、await 关键字,将其写成异步函数
————————————————
版权声明:本文为CSDN博主「mjzhang1993」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mjzhang1993/article/details/78752314
数据库操作
当涉及到数据库操作时,我们可以在 app 下再新增一个 service 目录。 将数据库操作从 controller 目录下分离出来放在 service 目录下,两个目录各司其职,一个专注业务处理,一个专注数据库层面的增删改查。另外再添加一个 model 目录,用来定义数据库表结构,具体的这里暂时不介绍了。
- error 事件
运行过程中一旦出错,Koa 会触发一个 error 事件,监听这个事件,可以处理错误,但是中间件中如果错误被 try…catch 捕获,则不会触发 error 事件,这个时候可以调用 ctx.app.emit() 手动释放 error 事件
app.on(‘error’, function (err) {
console.log(‘error Event’, err);
})
app.use(async (ctx, next) => {
ctx.body = 'in app';
try {
await next();
} catch (error) {
ctx.status = 404;
ctx.app.emit('error', error, ctx);
}
});
app.use((ctx) => {
ctx.body = 'error';
ctx.throw('error here');
})